package com.atguigu.tingshu.user.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.util.MongoUtil;
import com.atguigu.tingshu.model.user.UserListenProcess;
import com.atguigu.tingshu.user.service.UserListenProcessService;
import com.atguigu.tingshu.vo.album.TrackStatMqVo;
import com.atguigu.tingshu.vo.user.UserListenProcessVo;
import io.swagger.v3.core.util.Json;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@SuppressWarnings({"all"})
public class UserListenProcessServiceImpl implements UserListenProcessService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitService rabbitService;

    /**
     * 根据用户Id,声音Id 获取到播放进度
     * 将播放进度存到mongodb中，使用userid作为集合，因为保存的是每个人的播放进度，每个人的进度是不同的，所以存的是每个人的播放进度
     * @param trackId
     * @param userId
     * @return
     */
    @Override
    public BigDecimal getTrackBreakSecond(Long trackId, Long userId) {
        //	组成集合名称：
        String collectionName = MongoUtil.getCollectionName(MongoUtil.MongoCollectionEnum.USER_LISTEN_PROCESS, userId);
        //	从集合中获取对应的播放时长; userId and trackId;
        Query query = Query.query(Criteria.where("trackId").is(trackId));
        //在collectionName的集合中查询条还能是query（根据trackId查询播放进度），返回类型是UserListenProcess
        UserListenProcess userListenProcess = mongoTemplate.findOne(query, UserListenProcess.class, collectionName);
        //	判断
        if (null != userListenProcess){
            return userListenProcess.getBreakSecond();
        }
        //如果为空，说明此前没有播放过，就重头开始播放
        return new BigDecimal("0.00");
    }

    /**
     * 更新播放进度
     * 前端传过来了json，封装到UserListenProcessVo类中，传过来了专辑id，声音id，播放时间
     * @param userId
     * @param userListenProcessVo
     */
    @Override
    public void updateListenProcess(Long userId, UserListenProcessVo userListenProcessVo) {
        //根据用户id和声音id查出对应信息
        //集合名
        String collectionName = MongoUtil.getCollectionName(MongoUtil.MongoCollectionEnum.USER_LISTEN_PROCESS, userId);
        //查询条件
        Query query = new Query(Criteria.where("trackId").is(userListenProcessVo.getTrackId()));
        //在collectionName的集合中查询条还能是query（根据trackId查询播放进度），返回类型是UserListenProcess
        UserListenProcess userListenProcess = mongoTemplate.findOne(query, UserListenProcess.class, collectionName);
        if(null != userListenProcess){
            //说明mongodb中有数据，之前已经播放过，要更新播放时间和更新时间
            //修改更新时间
            userListenProcess.setUpdateTime(new Date());
            //修改播放进度
            userListenProcess.setBreakSecond(userListenProcessVo.getBreakSecond());
        }else {
            //说明mongodb中没有数据，之前没有播放过，保存信息
            //创建对象
            //	新增播放进度;
            userListenProcess = new UserListenProcess();
            //	赋值：
            userListenProcess.setUserId(userId);
            userListenProcess.setTrackId(userListenProcessVo.getTrackId());
            userListenProcess.setAlbumId(userListenProcessVo.getAlbumId());
            userListenProcess.setBreakSecond(userListenProcessVo.getBreakSecond());
            userListenProcess.setCreateTime(new Date());
            userListenProcess.setUpdateTime(new Date());
        }
        //无论是更新还是保存都需要将修改/新建的数据保存。
        mongoTemplate.save(userListenProcess,collectionName);//将信息保存到那个集合



        //为了防止恶意刷播放量，可以设置一个用户一天无论播放多少次播放量都只增加1
        //使用Redis的String的setnx分布式锁，在设置过期时间，第一次获取的时候播放量加一，后续24小时内拿不到锁，无法增加播放量
        //到了24小时，锁过期，此时在播放播放量可再次加1
        String key = userId + ":" + userListenProcess.getTrackId();
        //设置key，value无所谓，以为主要是判断key，所以此处设置value为1，有效时间是24小时
        Boolean result = this.redisTemplate.opsForValue().setIfAbsent(key, "1", 24, TimeUnit.HOURS);
        if(result){
            //如果setIfAbsent为false，说明不存在，说明是第一次播放，播放量可以加1
            //因为要修改别的微服务之间的数据，所以此处使用rabbitmq进行异步
            //更新播放量统计
            //	说明当前这个用户是第一次播放，专辑+声音；播放量+1;
            TrackStatMqVo trackStatMqVo = new TrackStatMqVo();
            trackStatMqVo.setCount(1);
            trackStatMqVo.setStatType(SystemConstant.TRACK_STAT_PLAY);
            trackStatMqVo.setTrackId(userListenProcess.getTrackId());
            trackStatMqVo.setAlbumId(userListenProcess.getAlbumId());
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            trackStatMqVo.setBusinessNo(uuid);
            rabbitService.sendMessage(MqConst.EXCHANGE_TRACK,MqConst.ROUTING_TRACK_STAT_UPDATE, JSON.toJSONString(trackStatMqVo));
        }


    }

    /**
     * 获取最近播放的记录（一条）
     * 我们需要根据用户Id 来获取播放记录 ，需要获取到专辑Id 与声音Id 封装到map中然后返回数据即可！
     * 如何知道最近播放的记录？ 是通过MongoDB中存储声音记录去查询！{按照 userId, updateTime 降序排序 取出 albumId,trackId}
     *
     *
     * @param userId
     * @return
     */
    @Override
    public Map<String, Object> getLatelyTrack(Long userId) {
        //创建map
        HashMap<String, Object> map = new HashMap<>();
        //	数据存储在MongoDB
        //集合名
        String collectionName = MongoUtil.getCollectionName(MongoUtil.MongoCollectionEnum.USER_LISTEN_PROCESS, userId);
        //查询条件
        Query query = new Query();
        //根据更新时间降序排序
        query.with(Sort.by(Sort.Direction.DESC,"update")).limit(1);
        UserListenProcess userListenProcess = mongoTemplate.findOne(query, UserListenProcess.class, collectionName);
        if(null !=userListenProcess){
            //取出来的数据不为空，存进map集合中
            map.put("albumId",userListenProcess.getAlbumId());
            map.put("trackId",userListenProcess.getTrackId());
        }
        //返回数据
        return map;
    }
}